package org.xx.armory.spring5.mvc.converters;

import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.GenericConverter;

import java.math.BigDecimal;
import java.util.Set;

import static org.xx.armory.commons.StringConverter.parseBigDecimal;
import static org.xx.armory.commons.StringConverter.parseByte;
import static org.xx.armory.commons.StringConverter.parseDouble;
import static org.xx.armory.commons.StringConverter.parseFloat;
import static org.xx.armory.commons.StringConverter.parseInteger;
import static org.xx.armory.commons.StringConverter.parseLong;
import static org.xx.armory.commons.StringConverter.parseShort;

public class StringToNumberConverter
        implements GenericConverter {
    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Set.of(
                new ConvertiblePair(String.class, Integer.class),
                new ConvertiblePair(String.class, int.class),
                new ConvertiblePair(String.class, Long.class),
                new ConvertiblePair(String.class, long.class),
                new ConvertiblePair(String.class, Short.class),
                new ConvertiblePair(String.class, short.class),
                new ConvertiblePair(String.class, Byte.class),
                new ConvertiblePair(String.class, byte.class),
                new ConvertiblePair(String.class, Float.class),
                new ConvertiblePair(String.class, float.class),
                new ConvertiblePair(String.class, Double.class),
                new ConvertiblePair(String.class, double.class),
                new ConvertiblePair(String.class, BigDecimal.class)
        );
    }

    @Override
    public Object convert(
            Object source,
            TypeDescriptor sourceType,
            TypeDescriptor targetType
    ) {
        final var s = source != null ? source.toString().strip() : "";
        final var type = targetType.getType();

        if (type.equals(Integer.class)) {
            return parseInteger(s, null);
        } else if (type.equals(int.class)) {
            return parseInteger(s, 0);
        } else if (type.equals(Long.class)) {
            return parseLong(s, null);
        } else if (type.equals(long.class)) {
            return parseLong(s, 0L);
        } else if (type.equals(Short.class)) {
            return parseShort(s, null);
        } else if (type.equals(short.class)) {
            return parseShort(s, (short) 0);
        } else if (type.equals(Byte.class)) {
            return parseByte(s, null);
        } else if (type.equals(byte.class)) {
            return parseByte(s, (byte) 0);
        } else if (type.equals(Float.class)) {
            return parseFloat(s, null);
        } else if (type.equals(float.class)) {
            return parseFloat(s, 0F);
        } else if (type.equals(Double.class)) {
            return parseDouble(s, null);
        } else if (type.equals(double.class)) {
            return parseDouble(s, 0D);
        } else if (type.equals(BigDecimal.class)) {
            return parseBigDecimal(s, null);
        } else {
            assert false : "Illegal target type: " + targetType;
            return null;
        }
    }
}
